package com.jmb.waimao.service.impl;

import com.jmb.waimao.entity.EmailTemplate;
import com.jmb.waimao.service.EmailTemplateService;
import com.jmb.waimao.service.MCPEmailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Implementation of the Mail Control Protocol (MCP) Email Service
 */
@Service
@Slf4j
public class MCPEmailServiceImpl implements MCPEmailService {

    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private EmailTemplateService templateService;

    @Value("${spring.mail.username:user@localhost}")
    private String fromEmail;

    @Value("${spring.mail.host:localhost}")
    private String host;

    @Value("${spring.mail.port:25}")
    private int port;

    @Value("${spring.mail.username:}")
    private String username;

    @Value("${spring.mail.password:}")
    private String password;

    @Override
    public boolean sendEmail(String to, String subject, String content) {
        try {
            log.info("MCP: Preparing to send email to: {}", to);
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setFrom(fromEmail);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true); // true indicates HTML content

            log.info("MCP: Sending email to: {} with subject: {}", to, subject);
            mailSender.send(message);
            log.info("MCP: Email sent successfully to: {}", to);
            return true;
        } catch (MessagingException e) {
            log.error("MCP: Failed to send email to {} due to messaging exception: {}", to, e.getMessage(), e);
            return false;
        } catch (Exception e) {
            log.error("MCP: Unexpected error sending email to {}: {}", to, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean sendEmailWithAttachments(String to, String subject, String content, Map<String, byte[]> attachments) {
        try {
            log.info("MCP: Preparing to send email with attachments to: {}", to);
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setFrom(fromEmail);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            // Add attachments
            if (attachments != null && !attachments.isEmpty()) {
                for (Map.Entry<String, byte[]> attachment : attachments.entrySet()) {
                    helper.addAttachment(
                            attachment.getKey(),
                            new ByteArrayResource(attachment.getValue())
                    );
                }
            }

            log.info("MCP: Sending email with {} attachments to: {}",
                    attachments != null ? attachments.size() : 0, to);
            mailSender.send(message);
            log.info("MCP: Email with attachments sent successfully to: {}", to);
            return true;
        } catch (MessagingException e) {
            log.error("MCP: Failed to send email with attachments to {}: {}", to, e.getMessage(), e);
            return false;
        } catch (Exception e) {
            log.error("MCP: Unexpected error sending email with attachments to {}: {}", to, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean sendTemplatedEmail(String to, String subject, Long templateId, Map<String, Object> variables) {
        try {
            log.info("MCP: Preparing to send templated email to: {}", to);

            // Convert variables to String map
            Map<String, String> stringVariables = new HashMap<>();
            if (variables != null) {
                for (Map.Entry<String, Object> entry : variables.entrySet()) {
                    stringVariables.put(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : "");
                }
            }

            // Get template and apply variables
            EmailTemplate template = templateService.getById(templateId);
            if (template == null) {
                log.error("MCP: Template with ID {} not found", templateId);
                return false;
            }

            EmailTemplate processedTemplate = templateService.applyTemplateVariables(templateId, stringVariables);

            // Use template subject if not provided
            String emailSubject = subject;
            if ((emailSubject == null || emailSubject.isEmpty()) && processedTemplate != null) {
                emailSubject = processedTemplate.getSubject();
            }

            // Send the email
            return sendEmail(to, emailSubject, processedTemplate.getContent());
        } catch (Exception e) {
            log.error("MCP: Failed to send templated email to {}: {}", to, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Map<String, Object> getStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("service", "MCP Email Service");
        status.put("status", "running");
        status.put("host", host);
        status.put("port", port);
        status.put("fromEmail", fromEmail);

        // Check connection to mail server
        boolean connected = checkConnection();
        status.put("connected", connected);

        return status;
    }

    @Override
    public boolean configure(Map<String, Object> config) {
        try {
            log.info("MCP: Configuring email service with new settings");

            JavaMailSenderImpl mailSenderImpl = (JavaMailSenderImpl) mailSender;

            // Update host if provided
            if (config.containsKey("host")) {
                String newHost = (String) config.get("host");
                mailSenderImpl.setHost(newHost);
                this.host = newHost;
                log.info("MCP: Updated host to: {}", newHost);
            }

            // Update port if provided
            if (config.containsKey("port")) {
                int newPort = ((Number) config.get("port")).intValue();
                mailSenderImpl.setPort(newPort);
                this.port = newPort;
                log.info("MCP: Updated port to: {}", newPort);
            }

            // Update username if provided
            if (config.containsKey("username")) {
                String newUsername = (String) config.get("username");
                mailSenderImpl.setUsername(newUsername);
                this.username = newUsername;
                log.info("MCP: Updated username to: {}", newUsername);
            }

            // Update password if provided
            if (config.containsKey("password")) {
                String newPassword = (String) config.get("password");
                mailSenderImpl.setPassword(newPassword);
                this.password = newPassword;
                log.info("MCP: Updated password");
            }

            // Update from email if provided
            if (config.containsKey("fromEmail")) {
                this.fromEmail = (String) config.get("fromEmail");
                log.info("MCP: Updated from email to: {}", this.fromEmail);
            }

            // Update JavaMail properties if provided
            if (config.containsKey("properties") && config.get("properties") instanceof Map) {
                Map<String, Object> props = (Map<String, Object>) config.get("properties");
                Properties javaMailProps = mailSenderImpl.getJavaMailProperties();

                for (Map.Entry<String, Object> entry : props.entrySet()) {
                    javaMailProps.put(entry.getKey(), entry.getValue().toString());
                    log.info("MCP: Updated property {}: {}", entry.getKey(), entry.getValue());
                }
            }

            // Configure default JavaMail properties for common SMTP servers
            Properties javaMailProps = mailSenderImpl.getJavaMailProperties();
            javaMailProps.put("mail.smtp.auth", "true");
            javaMailProps.put("mail.smtp.starttls.enable", "true");
            javaMailProps.put("mail.smtp.starttls.required", "true");
            javaMailProps.put("mail.debug", "true");

            // Special configuration for Gmail
            if ("smtp.gmail.com".equals(this.host)) {
                javaMailProps.put("mail.smtp.ssl.trust", "smtp.gmail.com");
            }

            // Special configuration for QQ Mail
            if ("smtp.qq.com".equals(this.host)) {
                javaMailProps.put("mail.smtp.ssl.trust", "smtp.qq.com");
            }

            // Special configuration for 163 Mail
            if ("smtp.163.com".equals(this.host)) {
                javaMailProps.put("mail.smtp.ssl.trust", "smtp.163.com");
            }

            return true;
        } catch (Exception e) {
            log.error("MCP: Failed to configure email service: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * Replace variables in a template
     *
     * @param template Template content
     * @param variables Variables to replace
     * @return Processed template
     */
    private String replaceVariables(String template, Map<String, Object> variables) {
        if (variables == null || variables.isEmpty()) {
            return template;
        }

        String result = template;
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String placeholder = "{{" + entry.getKey() + "}}";
            String value = entry.getValue() != null ? entry.getValue().toString() : "";
            result = result.replace(placeholder, value);
        }

        return result;
    }

    /**
     * Check connection to the mail server
     *
     * @return true if connected, false otherwise
     */
    private boolean checkConnection() {
        try {
            JavaMailSenderImpl mailSenderImpl = (JavaMailSenderImpl) mailSender;
            mailSenderImpl.testConnection();
            return true;
        } catch (Exception e) {
            log.warn("MCP: Failed to connect to mail server: {}", e.getMessage());
            return false;
        }
    }
}
